#region Using Directives
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Diagnostics; 
#endregion

namespace Minimal.Web
{
    /// <summary>
    /// A factory that creates SymmetricAlgorithms provided a string key.
    /// </summary>
    public class SymmetricAlgorithmFactory
        : ISymmetricAlgorithmFactory 
    {
        #region Constructor

        #endregion

        #region Properties

        #endregion        

        #region Methods
        #region GenerateIV
        /// <summary>
        /// Generates the initialization vector for the SymmetricAlgorithm.
        /// </summary>
        /// <param name="key">A string that can be used as a basis of the generated byte array.
        /// The same string always produces the same result. It's not required that the key
        /// is used in any way, different keys can therefore produce the same result.</param>
        /// <returns>A byte array.</returns>
        protected virtual byte[] GenerateIV(string key)
        {
            return new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
        }
        #endregion

        #region GenerateKey
        /// <summary>
        /// Generates the key to use with the SymmetricAlgorithm.
        /// </summary>
        /// <param name="key">A string to use as a basis of the generated key. The
        /// same string always produces the same result.</param>
        /// <returns>A byte array to be used as a key.</returns>
        protected virtual byte[] GenerateKey(string key)
        {
            return SymmetricAlgorithmFactory.GenerateKey(key, 16);
        }

        /// <summary>
        /// Generates a byte array from the given key-string.
        /// </summary>
        /// <param name="key">The string used as a basis for the byte array.</param>
        /// <param name="keyLength">The number of bytes to return.</param>
        /// <returns>A byte array.</returns>
        protected static byte[] GenerateKey(string key, int keyLength)
        {
            byte[] result = new byte[keyLength];
            byte[] keyBytes = Encoding.Unicode.GetBytes(key);

            for (int i = 0; i < keyBytes.Length; i++)
            {
                result[i % result.Length] ^= keyBytes[i];
            }
            return result;
        }
        #endregion

        #region GetAlgorithm
        /// <summary>
        /// Gets a SymmetricAlgorithm with key and IV set.
        /// </summary>
        /// <param name="key">A string key used as a basis for the
        /// key and IV of the algorithm.</param>
        /// <returns>A SymmetricAlgorithm.</returns>
        public SymmetricAlgorithm GetAlgorithm(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            SymmetricAlgorithm algorithm = this.GetAlgorithm(
                this.GenerateKey(key),
                this.GenerateIV(key));

            return algorithm;
        }

        /// <summary>
        /// Gets an algorithm with the key and IV set.
        /// </summary>
        /// <param name="key">The key to use.</param>
        /// <param name="iv">The IV to use.</param>
        /// <returns>A SymmetricAlgorithm ready for use.</returns>
        protected virtual SymmetricAlgorithm GetAlgorithm(byte[] key, byte[] iv)
        {
            SymmetricAlgorithm result = Rijndael.Create();
            result.Key = key;
            result.IV = iv;
            return result;
        }
        #endregion 
        #endregion
    }
}
